/*
* 
* Fichier source projet intel Acceler8 sous license GNU GPL v3.
* Voir http://www.gnu.org/copyleft/gpl.html pour plus d'informations
* La license est egalement disponible dans le repertoire /doc
* 
* Cree le : samedi 12 novembre 2011 à 18 : 20.
* Auteurs : Axel MOINET et Arnaud DURAND.
* 
* Nom de fichier : subseqcompute.cpp
* Chemin du fichier : ./src/classes/subseqcompute/subseqcompute.cpp
* 
* Description : Classe d'implémentation de calcul de sous-séquence.
* 			La fonction de calcul doit être lancée comme un thread POSIX.
* 
*/

#include "subseqcompute.h"

subSeqCompute::subSeqCompute(tbb::concurrent_vector<int> p_tabCgh, int p_g, int p_h, threadPrincipal *p_thread, FLAG lastCompute) {
	//if(p_tabCgh == NULL) {
		//Lancer une exception pointeur nul
	//}
	//else {
		this->tabCgh = p_tabCgh;
		this->thread = p_thread;
		this->a = 0;
		this->b = 0;
		this->g = p_g;
		this->h = p_h;
	//}
}

int subSeqCompute::launchCalcul() {
	//Création de la tache de calcul des PSUM :
	//this->psum = new tbb::concurrent_vector<int>();
	//this->smax = new tbb::concurrent_vector<int>();
	taskPsumSmax& taskPsumSmaxComputing = *new (tbb::task::allocate_child()) taskPsumSmax(&(this->tabCgh), &(this->psum), &(this->smax));

	//Création de la tache de calcul des SSUM :
	//this->ssum = new tbb::concurrent_vector<int>();
	//this->pmax = new tbb::concurrent_vector<int>();
	taskSsumPmax& taskSsumPmaxComputing = *new (tbb::task::allocate_child()) taskSsumPmax(&(this->tabCgh), &(this->ssum), &(this->pmax));

	tbb::task::set_ref_count(3);

	tbb::task::spawn( taskPsumSmaxComputing );
	tbb::task::spawn_and_wait_for_all( taskSsumPmaxComputing );
	return 0;
}

tbb::task* subSeqCompute::execute() {
	//std::cout << "Lancement du calcul" << std::endl;
	this->launchCalcul();
	//std::cout << "Calcul de M" << std::endl;
	this->computeM();
	//std::cout << "Recherche de A et B" << std::endl;
	this->findAB();
	//std::cout << "Comparaison des résultats" << std::endl;
	this->compareResults();

	return NULL;
}

int subSeqCompute::computeM() {
	//this->M = new tbb::concurrent_vector<int>();
	this->tabSize = this->tabCgh.size();

	for(int i=0; i < tabSize; i++) {
		this->M.push_back( this->pmax[i] + this->smax[i] + this->tabCgh[i] - this->ssum[i] - this->psum[i] );
	}

	return 0;
}

int subSeqCompute::findAB() {
	for(int i=1; i<this->tabSize; i++) {
		if( this->M[i] > this->M[a] ) {
			this->a = i;
			this->b = i;
		}
		else if( this->M[i] == this->M[a])
			this->b++;
	}
	return 0;
}

int subSeqCompute::compareResults() {
	struct result *resultFinal = (*(this->thread)).getStructureResult();
	tbb::spin_rw_mutex_v3::scoped_lock lock;

	//Acquisition de la mutex en lecture
	lock.acquire((*(this->thread)).mutexControlResult, false);
	if(this->M[a] > resultFinal->S) {
		lock.release();
		lock.acquire((*(this->thread)).mutexControlResult, true);
		if(this->M[a] > resultFinal->S) {
			resultFinal->S = this->M[a];
			resultFinal->a = this->a;
			resultFinal->b = this->b;
			resultFinal->g = this->g - 1;
			resultFinal->h = this->h - 1;
		}
		lock.release();
	}
	else {
		lock.release();
	}

	/*delete this->M;
	//delete this->tabCgh;
	delete this->pmax;
	delete this->psum;
	delete this->smax;
	delete this->ssum;*/

	return 0;
}
